/*
 * Copyright (c) 2023 fred
 * Licensed under the Apache License,Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

export class Position {
  private readonly _pos:number
  private readonly _lineNumber:number
  private readonly _columnNumber:number

  constructor(pos:number,lineNumber:number,columnNumber:number) {
    this._pos = pos
    this._lineNumber = lineNumber
    this._columnNumber = columnNumber
  }

  /**
   Gets the position index (0-based) of the original input source that this Position was read at. This tracks the
   total number of characters read into the source at this position, regardless of the number of preceeding lines.
   * @return the position, or {@code -1} if untracked.
   */
  public getPos():number {
    return this._pos
  }

  /**
   Gets the line number (1-based) of the original input source that this Position was read at.
   * @return the line number, or {@code -1} if untracked.
   */
  public getLineNumber():number {
    return this._lineNumber
  }

  /**
   Gets the cursor number (1-based) of the original input source that this Position was read at. The cursor number
   resets to 1 on every new line.
   * @return the cursor number, or {@code -1} if untracked.
   */
  public getColumnNumber():number {
    return this._columnNumber
  }

  private static _UntrackedPos = new Position(-1,-1,-1)
  /**
   Test if this position was tracked during parsing.
   * @return true if this was tracked during parsing, false otherwise (and all fields will be {@code -1}).
   */
  public isTracked():boolean {
    return this !== Position._UntrackedPos
  }

  /**
   Gets a String presentation of this Position, in the format {@code line,column:pos}.
   * @return a String
   */
  public toString():string {
    return this._lineNumber + "," + this._columnNumber + ":" + this._pos
  }

  public equals(o:any):boolean {
    if (this === o) {
      return true
    }
    if (o === undefined || o===null) {
      return false
    }
    if (!(o instanceof Position)) {
      return false
    }
    let position = o as Position
    if (this._pos !== position._pos) {
      return false
    }
    if (this._lineNumber !== position._lineNumber) {
      return false
    }
    return this._columnNumber === position._columnNumber
  }

  public hashCode():number {
    let result = this._pos
    result = 31*result + this._lineNumber
    result = 31*result + this._columnNumber
    return result
  }

}